package com.nulldev.util.crypto.api3.encryptors.p2pe2;

import java.math.BigInteger;
import java.nio.charset.Charset;

import com.nulldev.util.FinalBypass;
import com.nulldev.util.crypto.api2.Cryptable;
import com.nulldev.util.crypto.api2.EncryptionUtil;
import com.nulldev.util.crypto.api2.EncryptionUtil.Types;
import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.other.ArrayUtils;
import com.nulldev.util.string.StringsUtil;

@Deprecated
public class P2PE2 extends Cryptable {
	/*
	 * P2PE II plan
	 * 
	 * password -> char * password * password.length * password.hash
	 */
	
	public P2PE2() {
		super("p2pE.v2");
	}

	@Override
	public String encrypt(String object, String pass) {
		final BigInteger[] split = MathUtil.getValsB(object);
		final Integer[] pword = MathUtil.getVals(pass);
		for (int i = 0; i < split.length; i++) {
			final BigInteger val = split[i];
			BigInteger newVal = val;
			for (final int p : pword) {
				newVal = newVal.multiply(new BigInteger(String.valueOf(p)));
			}
			for (final int p : pword) {
				newVal = newVal.multiply(new BigInteger(String.valueOf(pass.length())));
			}
			split[i] = newVal;
		}
		return ArrayUtils.toSList(split);
	}

	@Override
	public String encrypt(String object, String pass, Charset charset) {
		return this.encrypt(object, pass);
	}

	@Override
	public String decrypt(String object, String pass) {
		final BigInteger[] split = MathUtil.getValsBi(object);
		final Integer[] pword = MathUtil.getVals(pass);
		//ArrayUtils.println(pword);
		for (int i = 0; i < split.length; i++) {
			final BigInteger val = split[i];
			BigInteger newVal = val;
			for (final int p : pword) {
				try {
					newVal = newVal.divide(new BigInteger(String.valueOf(p)));
				}catch (ArithmeticException e) {
					log.error("Expected decrypt failure. Reason: " + e.getMessage() + " | p = " + p + ", newVal = " + newVal.toString());
				}
			}
			for (final int p : pword) {
				try {
					newVal = newVal.divide(new BigInteger(String.valueOf(pass.length())));
				}catch (ArithmeticException e) {
					log.error("Expected decrypt failure. Reason: " + e.getMessage() + " | p = " + p + ", newVal = " + newVal.toString());
				}
			}
			split[i] = newVal;
		}
		return StringsUtil.toStandard(split);
	}

	@Override
	public String decrypt(String object, String pass, Charset charset) {
		return this.decrypt(object, pass);
	}

	@Override
	public String toPGPString(final String in) {
		final StringBuilder b = new StringBuilder();
		b.append("--START P2P BLOCK---").
			append(JVMUtil.lineSep()).
			append("Type: XE").
			append(JVMUtil.lineSep()).
			append("Iterations: 1").
			append(JVMUtil.lineSep()).
			append("Data: {" + in + "}").
			append(JVMUtil.lineSep()).
			append("----END P2P BLOCK---");
		return b.toString();
	}
	
	@Override
	public String toPGPString(final String in, final String key) {
		final StringBuilder b = new StringBuilder();
		b.append("--START P2P BLOCK---").
			append(JVMUtil.lineSep()).
			append("Type: XE").
			append(JVMUtil.lineSep()).
			append("Iterations: 1").
			append(JVMUtil.lineSep()).
			append("Key: " + key).
			append(JVMUtil.lineSep()).
			append("Data: {" + in + "}").
			append(JVMUtil.lineSep()).
			append("----END P2P BLOCK---");
		return b.toString();
	}
	
	@Override
	public String decryptFromPGP(final String in, final String key) {
		try {
			final FinalBypass<String> out = new FinalBypass<String>("default value");
			final String[] lines = StringsUtil.byLineSepeartor(in);
			boolean started = false;
			boolean ended = false;
			String pkey = key;
			String type = "";
			int iterations = -1;
			for (final String line : lines) {
				if (line.equals("--START P2P BLOCK---")) {
					started = true;
				}else if (line.equals("----END P2P BLOCK---")) {
					ended = true;
				}else if (line.startsWith("Iterations: ")){
					iterations = Integer.parseInt(line.substring(line.indexOf("Iterations: ") + 12));
				}else if (line.startsWith("Key: ")) {
					final String key_temp = StringsUtil.substringBetween(line, "Key: {", String.valueOf(line.charAt(line.length() - 1)));
					pkey = key_temp;
				}else if (line.startsWith("Type: ")) {
					type = line.substring(line.indexOf("Type: ") + 6);
					if (!type.equals("X-STANDARD") && !type.equals("X-LIST") && !type.equals("XE")) {
						throw new UnsupportedOperationException("Unsupported standard. (if not provided one, try 'X-STANDARD'.)");
					}
				}else if (line.startsWith("Data: {") && line.endsWith("}")) {
					if (iterations == -1) {
						this.log.warn("Iterations weren't provided, assuming that it's done once.");
						iterations = 1;
					}
					if (type.equals("X-STANDARD")) {
						final String o = EncryptionUtil.byType(Types.P2PX).decrypt(StringsUtil.fromIDL(StringsUtil.substringBetween(line, "Data: {", String.valueOf(line.charAt(line.length() - 1)))), pkey);
						out.setObject(o);
					}else if (type.equals("X-LIST")) {
						final String o = EncryptionUtil.byType(Types.P2PX).decrypt(StringsUtil.fromIDL(StringsUtil.substringBetween(line, "Data: {", String.valueOf(line.charAt(line.length() - 1)))), pkey);
						out.setObject(o);
					}else if (type.equals("XE")) {
						final String dta = StringsUtil.substringBetween(line, "Data: {", String.valueOf(line.charAt(line.length() - 1)));//"Data: {" +  String.valueOf(line.charAt(line.length() - 1)) + "}";
						final String o = EncryptionUtil.byType(Types.P2PE).decrypt(dta, pkey);
						out.setObject(o);
					}
				}
			}
			return out.getObject();
		}catch (Exception e) {
			e.printStackTrace();
			return "error";
		}
	}
}
